package waylines.waypoints
{
	import flash.geom.Point;
	import org.flintparticles.twoD.particles.Particle2D;
	import org.flintparticles.common.particles.Particle;
	import org.flintparticles.common.emitters.Emitter;
	import org.flintparticles.common.actions.ActionBase;

	public class FollowWaylines extends ActionBase
	{
		private const LINE_POINT_OLD:String = "po";
		private const LINE_POINT_NEW:String = "pn";
		private const LINE_TIME:String = "t";
		/**
		 * Whether the particles head for the first waypoint after passing through the last waypoint.
		 */
		public var loop:Boolean = false;
		/**
		 * Whether the particles' mass is taken into account. 
		 * If true, the acceleration applied to a particle is divided by the particle's mass.
		 */
		public var massless:Boolean = true;
		
		private var _waypoints:Array;

		public function FollowWaylines(waypoints : Array = null, loop : Boolean = false, massless : Boolean = true)
		{
			priority = -6;
			_waypoints = waypoints;
			this.loop = loop;
			this.massless = massless;
		}
		override public function update(emitter:Emitter, particle:Particle, time:Number):void 
		{
			if (!_waypoints.length) return;
			
			var linePointNew:Point;
			var linePointOld:Point;
			
			// дается частица
			var p2D:Particle2D = Particle2D(particle);
			
			if (!p2D.dictionary[FollowWaylines])
			{// в частицу помещаяется индекс текущей Точки Пути
				p2D.dictionary[FollowWaylines] = 1;
				// надо вычислить дельты координат для последующих Точек Пути
				var w:Wayline = _waypoints[0];
				// зона эмиттера совпадает с зоной первой Линии Пути (иначе последствия непредсказуемы)
				// запоминаем проекции
				p2D.dictionary[FollowWaylines+LINE_TIME] = w.line.getClosest(new Point(p2D.x, p2D.y));
				
				p2D.dictionary[FollowWaylines+LINE_POINT_OLD] = w.line.getPoint(p2D.dictionary[FollowWaylines+LINE_TIME]);
				p2D.dictionary[FollowWaylines+LINE_POINT_NEW] = Wayline(_waypoints[1]).line.getPoint(p2D.dictionary[FollowWaylines+LINE_TIME]);
			}
			// выясняется, к какой точке пути следует частица
			var index:int = p2D.dictionary[FollowWaylines];
			var waypoint:Wayline = _waypoints[index] as Wayline;
			
			linePointNew = p2D.dictionary[FollowWaylines+LINE_POINT_NEW];//waypoint.line.getPoint(p2D.dictionary[FollowWaylines+TIME]);
			
			// выясняется расстояние частицы от текущей Точки Пути 
			var dx:Number = p2D.x - linePointNew.x;
			var dy:Number = p2D.y - linePointNew.y;
			/*
			var dx:Number = pointNew.x - p2D.x;
			var dy:Number = pointNew.y - p2D.y;
			
			var speed:Number = 30;
			var length:Number = Math.sqrt(dx*dx + dy*dy);
			
			if(length > speed)
			{
				var factor:Number = speed/length;
				dx *= factor;
				dy *= factor;
			}
			else
			{
				var factor1:Number = length/speed;
				dx *= factor1;
				dy *= factor1;
			}
			p2D.velX = dx;
			p2D.velY = dy;
			*/
			
			// TODO вернуть Pool
			var r:Vec2D = new Vec2D(dx, dy);//Vec2DPool.get(dx, dy);
			var len:Number = r.length;
			if (len < waypoint.epsilon)
			{
				len = waypoint.epsilon;
			}
			
			r.length = -waypoint.strength * Math.pow(len, -0.5 * waypoint.attenuationPower);
			
			if (!massless)
			{
				r.length /= p2D.mass;
			}
			
			p2D.velX += r.x;
			p2D.velY += r.y;
			
			if(index > 0)
			{
				// выясним, достигает ли частица следущей Линии Пути --------------------
				// вычислить старую конкретную точку
				linePointOld = p2D.dictionary[FollowWaylines+LINE_POINT_OLD];//Wayline(_waypoints[index-1]).line.getPoint(p2D.dictionary[FollowWaylines+TIME]);
				// вычислить новую конкретную точку
				var pointCurrent:Point = new Point(p2D.x, p2D.y);
				//if(Point.distance(linePointOld, linePointNew) > Point.distance(linePointNew, pointCurrent))
				if(Point.distance(linePointOld, pointCurrent) > Point.distance(pointCurrent, linePointNew))
				{// частица проскочила Линию Пути - назначаем новую
					var nextIndex:int = index +1;
					
					if(nextIndex == _waypoints.length)
					{// частица достигла последней точки пути
						if(loop)
						{// зациклить
							nextIndex = 0;
							p2D.dictionary[FollowWaylines] = (nextIndex);
							p2D.dictionary[FollowWaylines+LINE_POINT_OLD] = p2D.dictionary[FollowWaylines+LINE_POINT_NEW];
							p2D.dictionary[FollowWaylines+LINE_POINT_NEW] = Wayline(_waypoints[nextIndex]).line.getPoint(p2D.dictionary[FollowWaylines+LINE_TIME]);
						}
						else
						{// уничтожить
							particle.isDead = true;
						}
					}
					else
					{// частица продолжает путь к своему концу
						p2D.dictionary[FollowWaylines] = (nextIndex);
						p2D.dictionary[FollowWaylines+LINE_POINT_OLD] = p2D.dictionary[FollowWaylines+LINE_POINT_NEW];
						p2D.dictionary[FollowWaylines+LINE_POINT_NEW] = Wayline(_waypoints[nextIndex]).line.getPoint(p2D.dictionary[FollowWaylines+LINE_TIME]);
					}
				}
				// TODO нужно диспатчить событие в конце пути, чтоб можно было подхватывать частицу
			}
		}
	}
}
